/**
 * 
 */
package tcss543.cpap.ashish;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import tcss543.cpap.common.ReviewerRank;
import tcss543.cpap.common.Utilities;

/**
 * Encapsulates a chromosome aka solution.
 * Comparison is based on fitness.
 * @author ashish
 * 
 */
public class Chromosome implements Comparable<Chromosome> {
	/**
	 * Each paper is a key of the map, and the set for each paper includes the
	 * reviewers assigned to it.
	 */
	private final Map<Short, Set<Short>> encoding;

	/**
	 * The quality of the chromosome
	 */
	private final BigDecimal quality;

	/**
	 * Constructor.
	 */
	public Chromosome(final Map<Short, Set<Short>> s,
			final Map<Short, Set<Short>> papers,
			final Map<Short, Map<Short, ReviewerRank>> reviewers) {
		encoding = s;
		quality = Utilities.calculateQuality(getSolution(papers, reviewers), papers, reviewers, false);
		if(!Utilities.atLeastMinimumReviewersPerPaper(encoding, papers)){
			throw new RuntimeException("Chromosome with less than required reviewers for a paper encountered.");
		}
	}

	/**
	 * Transform the encoding into a solution acceptable to calculate cost. i.e.
	 * the list of reviewers mapped to papers assigned.
	 * @param reviewers 
	 * @param papers 
	 * 
	 * @return the encoding
	 */
	public final Map<Short, Set<Short>> getSolution(Map<Short, Set<Short>> papers, Map<Short, Map<Short, ReviewerRank>> reviewers) {
		Map<Short, Set<Short>> solution = new HashMap<Short, Set<Short>>();

		//first allocate memory for all reviewers
		for (short r : reviewers.keySet()) {
			solution.put(r, new TreeSet<Short>());
		}
		
		//for every paper
		for (short p : encoding.keySet()) {
			//get reviewer
			for (short r : encoding.get(p)) {
				// add paper to reviewers paper list
				solution.get(r).add(p);
			}
		}

		
		return solution;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	@Override
	public int compareTo(Chromosome o) {
		// i need a descending sort
		return -1 * quality.compareTo(o.quality);
	}

	/**
	 * @return quality
	 */
	public BigDecimal getQuality() {
		return quality;
	}

	/**
	 * @return a deep copy of the encoding
	 */
	public final Map<Short, Set<Short>> getEncoding() {
		HashMap<Short, Set<Short>> r = new HashMap<Short, Set<Short>>();
		for(short k:encoding.keySet()){
			r.put(k, new TreeSet<Short>());
			for(short v: encoding.get(k)){
				r.get(k).add(v);
			}
			
		}
		return r;
	}
}
